package com.nanbei.a30;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class A30 {
    public static void main(String[] args) throws NoSuchMethodException {
        ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver();
        // 设置消息转换器
        resolver.setMessageConverters(Collections.singletonList(new MappingJackson2HttpMessageConverter()));
        // 设置参数解析器和返回值处理器
        resolver.afterPropertiesSet();

        // 测试json
        MockHttpServletRequest request = new MockHttpServletRequest();
        MockHttpServletResponse response = new MockHttpServletResponse();
/*        HandlerMethod handlerMethod = new HandlerMethod(new Controller1(), Controller1.class.getMethod("foo"));
        ArithmeticException exception = new ArithmeticException("被0除");
        resolver.resolveException(request, response, handlerMethod, exception);
        System.out.println(new String(response.getContentAsByteArray(),StandardCharsets.UTF_8));*/

        // 返回 mav
/*        HandlerMethod handlerMethod = new HandlerMethod(new Controller2(), Controller2.class.getMethod("foo"));
        ArithmeticException exception = new ArithmeticException("被0除");
        ModelAndView modelAndView = resolver.resolveException(request, response, handlerMethod, exception);
        System.out.println(modelAndView.getModel());
        System.out.println(modelAndView.getViewName());*/

        // 测试嵌套异常
/*        HandlerMethod handlerMethod = new HandlerMethod(new Controller3(), Controller3.class.getMethod("foo"));
        Exception exception = new Exception("E1", new RuntimeException("e2",new IOException("e3")));
        resolver.resolveException(request, response, handlerMethod, exception);
        System.out.println(new String(response.getContentAsByteArray(),StandardCharsets.UTF_8));*/

        // 测试异常处理方法参数解析
        HandlerMethod handlerMethod = new HandlerMethod(new Controller4(), Controller4.class.getMethod("foo"));
        Exception exception = new Exception("E1");
        resolver.resolveException(request, response, handlerMethod, exception);
        System.out.println(new String(response.getContentAsByteArray(),StandardCharsets.UTF_8));

        /*
            学到了什么
                a. ExceptionHandlerExceptionResolver 能够重用参数解析器、返回值处理器，实现组件重用
                b. 能够支持嵌套异常
         */
    }

    static class Controller1 {
        public void foo() {

        }
        @ExceptionHandler
        @ResponseBody
        public Map<String, Object> handle(ArithmeticException e) {
            Map<String, Object> map = new HashMap<>();
            map.put("error", e.getMessage());
            return map;
        }
    }

    static class Controller2 {
        public void foo() {

        }
        @ExceptionHandler
        public ModelAndView handle(ArithmeticException e) {
            Map<String, Object> map = new HashMap<>();
            map.put("error", e.getMessage());
            return new ModelAndView("test2", map);
        }
    }

    static class Controller3 {
        public void foo() {

        }
        @ExceptionHandler
        @ResponseBody
        public Map<String, Object> handle(IOException e3) {
            Map<String, Object> map = new HashMap<>();
            map.put("error", e3.getMessage());
            return map;
        }
    }

    static class Controller4 {
        public void foo() {}
        @ExceptionHandler
        @ResponseBody
        public Map<String, Object> handler(Exception e, HttpServletRequest request) {
            System.out.println(request);
            Map<String, Object> map = new HashMap<>();
            map.put("error", e.getMessage());
            return map;
        }
    }
}
